﻿#include "datetime.h"
#include <chrono>
#include <iomanip>
#include <limits.h>
#include <sstream>
#include <string.h>

#include <util/util.h>

#ifdef CPPC_OS_WINDOWS
#include <sys/timeb.h>
#include <Windows.h>
/// Linux的localtime_r函数在Windows上实现，将时间缀转换为时间结构体
#define localtime_r(t, tm) localtime_s(tm, t)
#define gmtime_r(t, tm) gmtime_s(tm, t)
#else
#include <sys/time.h>
#define strcmpi(s1, s2) strcasecmp(s1, s2)
#define sprintf_s snprintf
#endif // CPPC_OS_WINDOWS

using namespace std;

namespace cppc {

int DateTime::localTimeZone() {
#ifdef _WIN32
        struct _timeb timebuffer;
        _ftime(&timebuffer);
        return timebuffer.timezone * FACTOR_HOUR_TO_SEC;
#else
        int64_t timer = time(nullptr);
        struct tm *localTime = localtime(&timer);
        return localTime->tm_gmtoff;
#endif
}

bool DateTime::isLeapYear(int year) {
    return (year % 4 == 0 && ((year % 400 == 0) || (year % 100 != 0)));
}

int DateTime::getYearMonthDays(int year, int month) {
    switch (month) {
    case 1:
    case 3:
    case 5:
    case 7:
    case 8:
    case 10:
    case 12:
        return 31;
    case 4:
    case 6:
    case 9:
    case 11:
        return 30;
    case 2:
        // Need to consider a leap year in February
        return isLeapYear(year) ? 29 : 28;
    default:
        return 0;
    }
}

int64_t DateTime::currentTickCount() {
    // 获取当前的 tick count
    auto now = std::chrono::steady_clock::now();
    // 转换为 tick count，单位为毫秒
    return std::chrono::duration_cast<std::chrono::milliseconds>(now.time_since_epoch()).count();
}

DateTime DateTime::currentDateTime() {
    return std::move(DateTime());
}

int64_t DateTime::currentTimeStamp() {
    // 获取当前时刻的 time_point
    auto currentTimePoint = std::chrono::system_clock::now();

    // 转换为毫秒
    auto milliseconds = std::chrono::time_point_cast<std::chrono::milliseconds>(currentTimePoint);

    // 获取毫秒数
    return milliseconds.time_since_epoch().count();
}

DateTime::DateTime() {
    setTimestamp(DateTime::currentTimeStamp());
    m_valid = true;
}

DateTime::DateTime(int64_t stamp, int stampTimeZone) {
    setTimestamp(stamp, stampTimeZone);
    m_valid = true;
}

DateTime::DateTime(const tm &time) {
    m_tm = time;
    m_valid = true;
}

DateTime::DateTime(int year, int month, int day, int hour, int minute, int second, int millisecond, int stampTimeZone) {
    setDateTime(year, month, day, hour, minute, second, millisecond, stampTimeZone);
    m_valid = true;
}

DateTime::DateTime(const string &timeStr, const string &format, int stampTimeZone) {
    int t_day = 1;
    int t_month = 1;
    int t_year = UTC_SINCE_YEAR;
    int t_hour = 0;
    int t_minute = 0;
    int t_second = 0;
    int t_millisecond = 0;
    bool t_isPM = false;

    if (format.length() == 0 || format.length() != timeStr.length()) {
        setDateTime(t_year, t_month, t_day, t_hour, t_minute, t_second, t_millisecond, stampTimeZone);
        m_valid = false;
        return;
    }

    std::string retVal = "";
    std::string pattern_temp = "";
    try {
        for (unsigned int index_char = 0; index_char < format.length(); index_char++) {
            bool is_letter = false;
            if (((format[index_char] >= 'a') && (format[index_char] <= 'z'))
                || ((format[index_char] >= 'A') && (format[index_char] <= 'Z'))) {
                is_letter = true;
                if (pattern_temp.length() == 0) {
                    pattern_temp += format[index_char];
                } else if (format[index_char] == pattern_temp[pattern_temp.length() - 1]) {
                    pattern_temp += format[index_char];
                }
            }
            if ((pattern_temp.length() > 0)
                && ((format[index_char] != pattern_temp[pattern_temp.length() - 1])
                    || (index_char == format.length() - 1))) {
                int index_char_offset = (index_char == format.length() - 1) ? 1 : 0;
                if (pattern_temp == "yyyy") {
                    std::string t_valStr = timeStr.substr(index_char - 4 + index_char_offset, 4);
                    t_year = std::stoi(t_valStr);
                } else if (pattern_temp == "yy") {
                    std::string t_valStr = timeStr.substr(index_char - 2 + index_char_offset, 2);
                    t_year = std::stoi(t_valStr) + 2000;
                } else if (pattern_temp == "MM") {
                    std::string t_valStr = timeStr.substr(index_char - 2 + index_char_offset, 2);
                    t_month = std::stoi(t_valStr);
                } else if (pattern_temp == "M") {
                    std::string t_valStr = timeStr.substr(index_char - 1 + index_char_offset, 1);
                    t_month = std::stoi(t_valStr);
                } else if (pattern_temp == "dd") {
                    std::string t_valStr = timeStr.substr(index_char - 2 + index_char_offset, 2);
                    t_day = std::stoi(t_valStr);
                } else if (pattern_temp == "d") {
                    std::string t_valStr = timeStr.substr(index_char - 1 + index_char_offset, 1);
                    t_day = std::stoi(t_valStr);
                } else if (pattern_temp == "HH" || pattern_temp == "hh") {
                    std::string t_valStr = timeStr.substr(index_char - 2 + index_char_offset, 2);
                    t_hour = std::stoi(t_valStr);
                } else if (pattern_temp == "H" || pattern_temp == "h") {
                    std::string t_valStr = timeStr.substr(index_char - 1 + index_char_offset, 1);
                    t_hour = std::stoi(t_valStr);
                } else if (pattern_temp == "mm") {
                    std::string t_valStr = timeStr.substr(index_char - 2 + index_char_offset, 2);
                    t_minute = std::stoi(t_valStr);
                } else if (pattern_temp == "m") {
                    std::string t_valStr = timeStr.substr(index_char - 1 + index_char_offset, 1);
                    t_minute = std::stoi(t_valStr);
                } else if (pattern_temp == "ss") {
                    std::string t_valStr = timeStr.substr(index_char - 2 + index_char_offset, 2);
                    t_second = std::stoi(t_valStr);
                } else if (pattern_temp == "s") {
                    std::string t_valStr = timeStr.substr(index_char - 1 + index_char_offset, 1);
                    t_second = std::stoi(t_valStr);
                } else if (pattern_temp == "tt") {
                    std::string t_valStr = timeStr.substr(index_char - 2 + index_char_offset, 2);
                    t_isPM = t_valStr == "PM";
                } else if (pattern_temp == "zzz") {
                    std::string t_valStr = timeStr.substr(index_char - 3 + index_char_offset, 3);
                    t_millisecond = std::stoi(t_valStr);
                } else if (pattern_temp == "zz") {
                    std::string t_valStr = timeStr.substr(index_char - 2 + index_char_offset, 2);
                    t_millisecond = std::stoi(t_valStr);
                } else if (pattern_temp == "z") {
                    std::string t_valStr = timeStr.substr(index_char - 1 + index_char_offset, 1);
                    t_millisecond = std::stoi(t_valStr);
                }

                pattern_temp = "";
            }

            if (is_letter && pattern_temp.length() == 0) {
                pattern_temp += format[index_char];
            }
        }

        if (t_isPM) {
            t_hour += 12;
        }

        setDateTime(t_year, t_month, t_day, t_hour, t_minute, t_second, t_millisecond, stampTimeZone);
        m_valid = true;
    } catch (...) {
        setDateTime(t_year, t_month, t_day, t_hour, t_minute, t_second, t_millisecond, stampTimeZone);
        m_valid = false;
        return;
    }
}
DateTime::DateTime(const DateTime &other) {
    m_tm = other.m_tm;
    m_valid = other.m_valid;
}

DateTime::~DateTime() {
}

DateTime DateTime::clone() const {
    return DateTime(*this);
}

tm DateTime::getTm() const {
    return m_tm;
}

string DateTime::toString(const string &format) const {
    int t_day = day();
    int t_month = month();
    int t_year = year();
    int t_hour = hour();
    int t_minute = minute();
    int t_second = second();
    int t_millisecond = millisecond();

    if (format.length() == 0) {
        std::ostringstream oss;
        oss << setfill('0') << setw(4) << year()
            << "-" << setw(2) << month()
            << "-" << setw(2) << day()
            << " " << setw(2) << hour()
            << ":" << setw(2) << minute()
            << ":" << setw(2) << second()
            << "." << setw(3) << millisecond();
        return oss.str();
    }

    std::string retVal = "";
    std::string pattern_temp = "";
    for (unsigned int index_char = 0; index_char < format.length(); index_char++) {
        bool is_letter = false;
        if (((format[index_char] >= 'a') && (format[index_char] <= 'z')) || ((format[index_char] >= 'A') && (format[index_char] <= 'Z'))) {
            is_letter = true;
            if (pattern_temp.length() == 0) {
                pattern_temp += format[index_char];
            } else if (format[index_char] == pattern_temp[pattern_temp.length() - 1]) {
                pattern_temp += format[index_char];
            }
        }
        if ((pattern_temp.length() > 0) && ((format[index_char] != pattern_temp[pattern_temp.length() - 1]) || (index_char == format.length() - 1))) {
            // int *ptr_date_section = nullptr;
            char value_converted[5] = "";
            if (pattern_temp == "yyyy") {
                sprintf_s(value_converted, 5, "%04d", t_year);
                retVal += value_converted;
            } else if (pattern_temp == "yy") {
                sprintf_s(value_converted, 5, "%02d", t_year % 100);
                retVal += value_converted;
            } else if (pattern_temp == "MM") {
                sprintf_s(value_converted, 5, "%02d", t_month);
                retVal += value_converted;
            } else if (pattern_temp == "M") {
                sprintf_s(value_converted, 5, "%01d", t_month);
                retVal += value_converted;
            } else if (pattern_temp == "dd") {
                sprintf_s(value_converted, 5, "%02d", t_day);
                retVal += value_converted;
            } else if (pattern_temp == "d") {
                sprintf_s(value_converted, 5, "%01d", t_day);
                retVal += value_converted;
            } else if (pattern_temp == "HH") {
                sprintf_s(value_converted, 5, "%02d", t_hour);
                retVal += value_converted;
            } else if (pattern_temp == "H") {
                sprintf_s(value_converted, 5, "%01d", t_hour);
                retVal += value_converted;
            } else if (pattern_temp == "hh") {
                int instance_hour = t_hour;
                if (instance_hour == 0) {
                    retVal += "12";
                } else if (instance_hour > 12) {
                    sprintf_s(value_converted, 5, "%02d", instance_hour - 12);
                    retVal += value_converted;
                } else {
                    sprintf_s(value_converted, 5, "%02d", instance_hour);
                    retVal += value_converted;
                }
            } else if (pattern_temp == "h") {
                int instance_hour = t_hour;
                if (instance_hour == 0) {
                    retVal += "12";
                } else if (instance_hour > 12) {
                    sprintf_s(value_converted, 5, "%01d", instance_hour - 12);
                    retVal += value_converted;
                } else {
                    sprintf_s(value_converted, 5, "%01d", instance_hour);
                    retVal += value_converted;
                }
            } else if (pattern_temp == "mm") {
                sprintf_s(value_converted, 5, "%02d", t_minute);
                retVal += value_converted;
            } else if (pattern_temp == "m") {
                sprintf_s(value_converted, 5, "%01d", t_minute);
                retVal += value_converted;
            } else if (pattern_temp == "ss") {
                sprintf_s(value_converted, 5, "%02d", t_second);
                retVal += value_converted;
            } else if (pattern_temp == "s") {
                sprintf_s(value_converted, 5, "%01d", t_second);
                retVal += value_converted;
            } else if (pattern_temp == "tt") {
                if (t_hour >= 12) {
                    retVal += "PM";
                } else {
                    retVal += "AM";
                }
            } else if (pattern_temp == "zzz") {
                sprintf_s(value_converted, 5, "%03d", t_millisecond);
                retVal += value_converted;
            } else if (pattern_temp == "zz") {
                sprintf_s(value_converted, 5, "%02d", t_millisecond);
                retVal += value_converted;
            } else if (pattern_temp == "z") {
                sprintf_s(value_converted, 5, "%01d", t_millisecond);
                retVal += value_converted;
            } else {
                retVal += pattern_temp;
            }

            pattern_temp = "";
        }

        if (!is_letter) {
            retVal += format[index_char];
        } else if (pattern_temp.length() == 0) {
            pattern_temp += format[index_char];
        }
    }
    return retVal;
}

bool DateTime::valid() {
    return m_valid;
}

int DateTime::year() const {
    return m_tm.tm_year + TM_SINCE_YEAR;
}

int DateTime::month() const {
    return m_tm.tm_mon + 1;
}

int DateTime::day() const {
    return m_tm.tm_mday;
}

int DateTime::hour() const {
    return m_tm.tm_hour;
}

int DateTime::minute() const {
    return m_tm.tm_min;
}

int DateTime::second() const {
    return m_tm.tm_sec;
}

int DateTime::millisecond() const {
    return m_millisecond;
}

int DateTime::yearDay() const {
    return m_tm.tm_yday + 1;
}

int DateTime::weekDay() const {
    return m_tm.tm_wday == 0 ? 7 : m_tm.tm_wday;
}

int64_t DateTime::timestamp() const {
    int64_t secs = 0;
    {
        int year = m_tm.tm_year + TM_SINCE_YEAR;
        for (short y = UTC_SINCE_YEAR; y < year; ++y) {
            secs += int64_t((cppc::DateTime::isLeapYear(y) ? 366 : 365) * FACTOR_DAY_TO_SEC);
        }
        for (short m = 0; m < m_tm.tm_mon; ++m) {
            secs += int64_t(cppc::DateTime::getYearMonthDays(year, m + 1) * FACTOR_DAY_TO_SEC);
        }
        secs += int64_t((m_tm.tm_mday - 1) * FACTOR_DAY_TO_SEC);
        secs += int64_t(m_tm.tm_hour * FACTOR_HOUR_TO_SEC);
        secs += int64_t(m_tm.tm_min * FACTOR_MIN_TO_SEC);
        secs += int64_t(m_tm.tm_sec);
    }
    return (secs - tm_gmtoff) * FACTOR_SEC_TO_MILLI + m_millisecond;
}

int DateTime::timeZone() const {
    return tm_gmtoff / FACTOR_HOUR_TO_MILLI;
}

int DateTime::timeZoneOffset() const {
    return tm_gmtoff;
}

void DateTime::setTimestamp(int64_t stamp, int stampTimeZone) {
    int64_t stampSec = stamp / FACTOR_SEC_TO_MILLI + ((int64_t)stampTimeZone) * FACTOR_HOUR_TO_MILLI;
    gmtime_r(&stampSec, &m_tm);
    tm_gmtoff = stampTimeZone * FACTOR_HOUR_TO_MILLI;

    m_millisecond = stamp % FACTOR_SEC_TO_MILLI;
}

DateTime &DateTime::setDateTime(int year, int month, int day, int hour, int minute, int second, int millisecond, int stampTimeZone) {
    m_tm.tm_year = year - TM_SINCE_YEAR;
    m_tm.tm_mon = max(0, min(month - 1, 11));
    m_tm.tm_mday = max(0, min(day, 31));
    m_tm.tm_hour = max(0, min(hour, 23));
    m_tm.tm_min = max(0, min(minute, 59));
    m_tm.tm_sec = max(0, min(second, 59));
    m_millisecond = max(0, min(millisecond, 999));
    tm_gmtoff = stampTimeZone * FACTOR_HOUR_TO_MILLI;

    update();
    return *this;
}

DateTime &DateTime::setYear(int year) {
    m_tm.tm_year = year - TM_SINCE_YEAR;
    update();
    return *this;
}

DateTime &DateTime::setMonth(int month) {
    m_tm.tm_mon = max(0, min(month - 1, 11));
    update();
    return *this;
}

DateTime &DateTime::setDay(int day) {
    m_tm.tm_mday = max(0, min(day, 31));
    update();
    return *this;
}

DateTime &DateTime::setHour(int hour) {
    m_tm.tm_hour = max(0, min(hour, 23));
    return *this;
}

DateTime &DateTime::setMinute(int minute) {
    m_tm.tm_min = max(0, min(minute, 59));
    return *this;
}

DateTime &DateTime::setSecond(int second) {
    m_tm.tm_sec = max(0, min(second, 59));
    return *this;
}

DateTime &DateTime::setMilliSecond(int millisecond) {
    m_millisecond = max(0, min(millisecond, 999));
    return *this;
}

DateTime &DateTime::zeroSet(TimeSpan::Period period) {
    switch (period) {
    case TimeSpan::Minute:
        m_tm.tm_sec = 0;
        m_millisecond = 0;
        break;
    case TimeSpan::Hour:
        m_tm.tm_min = 0;
        m_tm.tm_sec = 0;
        m_millisecond = 0;
        break;
    case TimeSpan::Day:
        m_tm.tm_hour = 0;
        m_tm.tm_min = 0;
        m_tm.tm_sec = 0;
        m_millisecond = 0;
        break;
    case TimeSpan::Month:
        m_tm.tm_mday = 1;
        m_tm.tm_hour = 0;
        m_tm.tm_min = 0;
        m_tm.tm_sec = 0;
        m_millisecond = 0;
        break;
    case TimeSpan::Year:
        m_tm.tm_mon = 0;
        m_tm.tm_mday = 1;
        m_tm.tm_hour = 0;
        m_tm.tm_min = 0;
        m_tm.tm_sec = 0;
        m_millisecond = 0;
        break;
    default:
        break;
    }

    return *this;
}

DateTime &DateTime::add(long long value, TimeSpan::Period period) {
    switch (period) {
    case TimeSpan::MilliSecond:
        addMilliSecond(value);
        break;
    case TimeSpan::Second:
        addSecond(value);
        break;
    case TimeSpan::Minute:
        addMinute(value);
        break;
    case TimeSpan::Hour:
        addHour(value);
        break;
    case TimeSpan::Day:
        addDay(value);
        break;
    case TimeSpan::Week:
        addWeek(value);
        break;
    case TimeSpan::Month:
        addMonth(value);
        break;
    case TimeSpan::Year:
        addYear(value);
        break;
    default:
        break;
    }

    return *this;
}

DateTime &DateTime::add(const TimeSpan &duration) {
    return add(duration.value(), duration.period());
}

DateTime &DateTime::addYear(int value) {
    m_tm.tm_year += value;
    if (m_tm.tm_year < 0) {
        m_tm.tm_year = 0;
    }

    int monthDays = DateTime::getYearMonthDays(year(), month());
    if (m_tm.tm_mday > monthDays) {
        m_tm.tm_mday = monthDays;
    }

    return *this;
}

DateTime &DateTime::addMonth(int value) {
    m_tm.tm_mon += value;
    m_tm.tm_year += m_tm.tm_mon / 12;
    m_tm.tm_mon = m_tm.tm_mon % 12;
    if (m_tm.tm_mon < 0) {
        m_tm.tm_year -= 1;
        m_tm.tm_mon += 12;
    }

    int monthDays = DateTime::getYearMonthDays(year(), month());
    if (m_tm.tm_mday > monthDays) {
        m_tm.tm_mday = monthDays;
    }

    return *this;
}

DateTime &DateTime::addWeek(int value) {
    setTimestamp(timestamp() + value * FACTOR_WEEK_TO_MILLI);
    return *this;
}

DateTime &DateTime::addDay(int value) {
    setTimestamp(timestamp() + value * FACTOR_DAY_TO_MILLI);
    return *this;
}

DateTime &DateTime::addHour(int value) {
    setTimestamp(timestamp() + value * FACTOR_HOUR_TO_MILLI);
    return *this;
}

DateTime &DateTime::addMinute(int value) {
    setTimestamp(timestamp() + value * FACTOR_MIN_TO_MILLI);
    return *this;
}

DateTime &DateTime::addSecond(int value) {
    setTimestamp(timestamp() + value * FACTOR_SEC_TO_MILLI);
    return *this;
}

DateTime &DateTime::addMilliSecond(int value) {
    setTimestamp(timestamp() + value);
    return *this;
}

long long DateTime::diff(const DateTime &other, TimeSpan::Period period) {
    switch (period) {
    case TimeSpan::MilliSecond:
        return static_cast<long long>(getUTCFullMilliSeconds() - other.getUTCFullMilliSeconds());
    case TimeSpan::Second:
        return static_cast<long long>(getUTCFullSeconds() - other.getUTCFullSeconds());
    case TimeSpan::Minute:
        return static_cast<long long>(getUTCFullMinutes() - other.getUTCFullMinutes());
    case TimeSpan::Hour:
        return static_cast<long long>(getUTCFullHours() - other.getUTCFullHours());
    case TimeSpan::Day:
        return static_cast<long long>(getUTCFullDays() - other.getUTCFullDays());
    case TimeSpan::Week:
        return static_cast<long long>(getUTCFullWeeks() - other.getUTCFullWeeks());
    case TimeSpan::Month:
        return static_cast<long long>(getUTCFullMonths() - other.getUTCFullMonths());
    case TimeSpan::Year:
        return static_cast<long long>(getUTCFullYears() - other.getUTCFullYears());
    default:
        return 0;
    }
}

int DateTime::getUTCFullMonths() const {
    return year() * 12 + month() - 1;
}

int DateTime::getUTCFullYears() const {
    return year();
}

long long DateTime::getUTCFullMilliSeconds() const {
    return timestamp();
}

int64_t DateTime::getUTCFullSeconds() const {
    return timestamp() / FACTOR_SEC_TO_MILLI;
}

int DateTime::getUTCFullMinutes() const {
    return static_cast<int>((timestamp() / FACTOR_MIN_TO_MILLI));
}

int DateTime::getUTCFullHours() const {
    return static_cast<int>((timestamp() / FACTOR_HOUR_TO_MILLI));
}

int DateTime::getUTCFullDays() const {
    return static_cast<int>((timestamp() / FACTOR_DAY_TO_MILLI));
}

int DateTime::getUTCFullWeeks() const {
    int days = getUTCFullDays() + 4;
    int weeks = (days - 1) / 7;
    int weekDay = days % 7;
    if (weekDay < 0) {
        weeks -= 1;
    }
    return weeks;
}

bool DateTime::isLeapYear() const {
    return DateTime::isLeapYear(year());
}

bool DateTime::isLastDayOfMonth() const {
    return day() >= DateTime::getYearMonthDays(year(), month());
}

DateTime DateTime::operator+(const TimeSpan &duration) {
    return clone().add(duration.value(), duration.period());
}

DateTime DateTime::operator-(const TimeSpan &duration) {
    return clone().add(-duration.value(), duration.period());
}

TimeSpan DateTime::operator-(const DateTime &other) {
    return TimeSpan(static_cast<long long>(timestamp() - other.timestamp()));
}

DateTime &DateTime::operator+=(const TimeSpan &duration) {
    return add(duration.value(), duration.period());
}

DateTime &DateTime::operator-=(const TimeSpan &duration) {
    return add(-duration.value(), duration.period());
}

bool DateTime::operator<(const DateTime &other) {
    if (m_tm.tm_year != other.m_tm.tm_year) {
        return m_tm.tm_year < other.m_tm.tm_year;
    }

    if (m_tm.tm_mon != other.m_tm.tm_mon) {
        return m_tm.tm_mon < other.m_tm.tm_mon;
    }

    if (m_tm.tm_mday != other.m_tm.tm_mday) {
        return m_tm.tm_mday < other.m_tm.tm_mday;
    }

    if (m_tm.tm_hour != other.m_tm.tm_hour) {
        return m_tm.tm_hour < other.m_tm.tm_hour;
    }

    if (m_tm.tm_min != other.m_tm.tm_min) {
        return m_tm.tm_min < other.m_tm.tm_min;
    }

    if (m_tm.tm_sec != other.m_tm.tm_sec) {
        return m_tm.tm_sec < other.m_tm.tm_sec;
    }

    return m_millisecond < other.m_millisecond;
}

bool DateTime::operator>(const DateTime &other) {
    if (m_tm.tm_year != other.m_tm.tm_year) {
        return m_tm.tm_year > other.m_tm.tm_year;
    }

    if (m_tm.tm_mon != other.m_tm.tm_mon) {
        return m_tm.tm_mon > other.m_tm.tm_mon;
    }

    if (m_tm.tm_mday != other.m_tm.tm_mday) {
        return m_tm.tm_mday > other.m_tm.tm_mday;
    }

    if (m_tm.tm_hour != other.m_tm.tm_hour) {
        return m_tm.tm_hour > other.m_tm.tm_hour;
    }

    if (m_tm.tm_min != other.m_tm.tm_min) {
        return m_tm.tm_min > other.m_tm.tm_min;
    }

    if (m_tm.tm_sec != other.m_tm.tm_sec) {
        return m_tm.tm_sec > other.m_tm.tm_sec;
    }

    return m_millisecond > other.m_millisecond;
}

bool DateTime::operator==(const DateTime &other) {
    return (m_tm.tm_year == other.m_tm.tm_year) && (m_tm.tm_mon == other.m_tm.tm_mon)
           && (m_tm.tm_mday == other.m_tm.tm_mday) && (m_tm.tm_hour == other.m_tm.tm_hour)
           && (m_tm.tm_min == other.m_tm.tm_min) && (m_tm.tm_sec == other.m_tm.tm_sec)
           && (m_millisecond == other.m_millisecond);
}

void DateTime::update() {
    int monthDays = DateTime::getYearMonthDays(year(), month());
    if (m_tm.tm_mday > monthDays) {
        m_tm.tm_mday = monthDays;
    }

    setTimestamp(timestamp(), timeZone());
}
} // namespace cppc
